﻿// sevenzip_cracker.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <chrono>
#include <cstdlib>
#include <filesystem>
#include <limits>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX    // 防止 windows.h 定义 min/max 宏
#endif
#include <windows.h>
#define NULL_DEVICE "nul"
#else
#define NULL_DEVICE "/dev/null"
#endif

class SevenZipCracker {
private:
	std::string zipFilePath;
	uint64_t attempts;
	std::chrono::steady_clock::time_point startTime;
	std::string tempDir;

public:
	SevenZipCracker(const std::string& filePath)
		: zipFilePath(filePath), attempts(0) {
		startTime = std::chrono::steady_clock::now();

		// 创建唯一临时目录
		auto ts = std::chrono::system_clock::now().time_since_epoch().count();
		tempDir = "temp_extract_" + std::to_string(ts);
		try {
			std::filesystem::create_directory(tempDir);
		}
		catch (...) {
			// 若创建失败，程序仍可继续（会按需尝试创建）
		}
	}

	~SevenZipCracker() {
		// 程序结束时清理临时目录（若留要保留文件请注释掉）
		try {
			if (std::filesystem::exists(tempDir)) {
				std::filesystem::remove_all(tempDir);
			}
		}
		catch (...) {}
	}

	// 检查7z是否可用
	static bool check7zAvailable() {
		// 尝试运行 "7z -h" 并检查返回码
		std::string cmd = "7z -h > " + std::string(NULL_DEVICE) + " 2>&1";
		int r = std::system(cmd.c_str());
		// system 返回 -1 表示出错；在大多数平台上 7z 可用时返回 0
		return (r == 0);
	}

	// 将密码做简单的 shell 引号包装（双引号内部的双引号转义为 \")
	static std::string shellQuote(const std::string& s) {
		std::string out;
		out += "\"";
		for (char c : s) {
			if (c == '"') out += "\\\"";
			else if (c == '\\') out += "\\\\";
			else out += c;
		}
		out += "\"";
		return out;
	}

	// 尝试使用密码（先用 `7z t` 测试，测试通过则用 `7z x` 解压到 tempDir 并列出）
	bool tryPassword(const std::string& password) {
		attempts++;

		// 使用 7z t 来测试密码是否正确（更快、更可靠）
		std::string quotedPass = shellQuote(password);
		std::string quotedArchive = shellQuote(zipFilePath);

#ifdef _WIN32
		std::string testCmd = "7z t -p" + quotedPass + " " + quotedArchive + " > " + std::string(NULL_DEVICE) + " 2>&1";
#else
		std::string testCmd = "7z t -p" + quotedPass + " " + quotedArchive + " > " + std::string(NULL_DEVICE) + " 2>&1";
#endif

		int testResult = std::system(testCmd.c_str());

		if (testResult == 0) {
			// 密码测试通过 — 现在真正解压到 tempDir，列出解压后的文件
			try {
				if (!std::filesystem::exists(tempDir)) {
					std::filesystem::create_directory(tempDir);
				}
			}
			catch (...) {
				// ignore
			}

#ifdef _WIN32
			std::string extractCmd = "7z x -p" + quotedPass + " " + quotedArchive + " -o" + shellQuote(tempDir) + " -y > " + std::string(NULL_DEVICE) + " 2>&1";
#else
			std::string extractCmd = "7z x -p" + quotedPass + " " + quotedArchive + " -o" + shellQuote(tempDir) + " -y > " + std::string(NULL_DEVICE) + " 2>&1";
#endif
			int extractResult = std::system(extractCmd.c_str());
			// 即使 extractResult 非 0，我们也认为密码正确（因为 testResult 已为 0）
			// 检查 tempDir 是否有文件（递归）
			bool hasFiles = hasExtractedFiles(tempDir);

			auto endTime = std::chrono::steady_clock::now();
			auto duration = std::chrono::duration_cast<std::chrono::seconds>(endTime - startTime);

			std::cout << "\n✅ 密码破解成功！" << std::endl;
			std::cout << "📝 密码: " << password << std::endl;
			std::cout << "🔢 尝试次数: " << attempts << std::endl;
			std::cout << "⏱️ 耗时: " << duration.count() << " 秒" << std::endl;
			if (hasFiles) {
				std::cout << "📁 文件已解压到: " << tempDir << std::endl;
				std::cout << "解压后的文件列表：" << std::endl;
				listExtractedFiles(tempDir);
			}
			else {
				std::cout << "⚠️ 通过测试确认密码正确，但未能从压缩包中列出文件（可能为压缩包特殊结构）" << std::endl;
				std::cout << "你可以手动运行：7z x -p" << password << " " << zipFilePath << " -o" << tempDir << std::endl;
			}
			return true;
		}

		if (attempts % 100 == 0) {
			std::cout << "已尝试 " << attempts << " 个密码..." << std::endl;
		}

		return false;
	}

	// 常用密码攻击
	bool commonPasswordAttack() {
		std::vector<std::string> commonPasswords = {
			"123", "1234", "12345", "123456", "1234567", "12345678", "123456789", "1234567890",
			"000", "0000", "00000", "000000", "0000000", "00000000",
			"111", "1111", "11111", "111111", "1111111", "11111111",
			"888", "8888", "88888", "888888", "8888888", "88888888",
			"a", "aa", "aaa", "aaaa", "aaaaa", "aaaaaa",
			"abc", "abcd", "abcde", "abcdef",
			"qwerty", "qwertyuiop", "asdfgh", "zxcvbn",
			"password", "password1", "password123",
			"admin", "admin123", "root", "root123",
			"test", "test123", "demo", "demo123",
			"1qaz", "2wsx", "3edc", "4rfv", "5tgb", "6yhn", "7ujm", "8ik", "9ol", "0p",
			"2020", "2021", "2022", "2023", "2024", "2025",
			"hello", "world", "love", "secret", "pass", "key",
			"file", "data", "document", "archive",
			"zip", "7z", "rar", "compress",
			"", " "
		};

		std::cout << "🔍 开始常用密码攻击 (" << commonPasswords.size() << " 个密码)..." << std::endl;

		for (const auto& p : commonPasswords) {
			if (tryPassword(p)) return true;
		}
		std::cout << "❌ 常用密码攻击完成，未找到正确密码" << std::endl;
		return false;
	}

	// 字典攻击
	bool dictionaryAttack(const std::string& dictionaryFile) {
		std::ifstream file(dictionaryFile);
		if (!file.is_open()) {
			std::cerr << "❌ 无法打开字典文件: " << dictionaryFile << std::endl;
			return false;
		}
		std::string password;
		std::cout << "🔍 开始字典攻击..." << std::endl;
		while (std::getline(file, password)) {
			// 去除残留回车
			if (!password.empty() && password.back() == '\r') password.pop_back();
			if (tryPassword(password)) return true;
		}
		std::cout << "❌ 字典攻击完成，未找到正确密码" << std::endl;
		return false;
	}

	// 数字暴力破解
	bool bruteForceNumeric(int maxLength) {
		std::cout << "🔍 开始数字暴力破解 (长度: 1-" << maxLength << ")..." << std::endl;
		const std::string charset = "0123456789";
		for (int length = 1; length <= maxLength; ++length) {
			std::cout << "正在尝试 " << length << " 位数字..." << std::endl;
			if (bruteForceRecursive("", length, charset)) return true;
		}
		std::cout << "❌ 数字暴力破解完成，未找到正确密码" << std::endl;
		return false;
	}

	// 小写字母暴力破解
	bool bruteForceLowercase(int maxLength) {
		std::cout << "🔍 开始小写字母暴力破解 (长度: 1-" << maxLength << ")..." << std::endl;
		const std::string charset = "abcdefghijklmnopqrstuvwxyz";
		for (int length = 1; length <= maxLength; ++length) {
			std::cout << "正在尝试 " << length << " 位小写字母..." << std::endl;
			if (bruteForceRecursive("", length, charset)) return true;
		}
		std::cout << "❌ 小写字母暴力破解完成，未找到正确密码" << std::endl;
		return false;
	}

	// 混合字符暴力破解
	bool bruteForceMixed(int maxLength) {
		std::cout << "🔍 开始混合字符暴力破解 (长度: 1-" << maxLength << ")..." << std::endl;
		const std::string charset = "abcdefghijklmnopqrstuvwxyz0123456789";
		for (int length = 1; length <= maxLength; ++length) {
			std::cout << "正在尝试 " << length << " 位混合字符..." << std::endl;
			if (bruteForceRecursive("", length, charset)) return true;
		}
		std::cout << "❌ 混合字符暴力破解完成，未找到正确密码" << std::endl;
		return false;
	}

	// 显示统计信息
	void showStats() {
		auto currentTime = std::chrono::steady_clock::now();
		auto dur = std::chrono::duration_cast<std::chrono::seconds>(currentTime - startTime);
		std::cout << "\n📊 统计信息:" << std::endl;
		std::cout << "尝试次数: " << attempts << std::endl;
		std::cout << "运行时间: " << dur.count() << " 秒" << std::endl;
		if (dur.count() > 0) {
			std::cout << "平均速度: " << (attempts / dur.count()) << " 密码/秒" << std::endl;
		}
	}

private:
	// 递归生成组合
	bool bruteForceRecursive(const std::string& current, int length, const std::string& charset) {
		if ((int)current.length() == length) {
			return tryPassword(current);
		}
		for (char c : charset) {
			if (bruteForceRecursive(current + c, length, charset)) return true;
		}
		return false;
	}

	// 递归检查目录下是否有任何 regular file
	static bool hasExtractedFiles(const std::string& dir) {
		try {
			if (!std::filesystem::exists(dir)) return false;
			for (auto& entry : std::filesystem::recursive_directory_iterator(dir)) {
				std::error_code ec;
				if (entry.is_regular_file(ec)) return true;
			}
		}
		catch (...) {}
		return false;
	}

	// 列出解压后的文件（递归）
	static void listExtractedFiles(const std::string& dir) {
		try {
			for (auto& entry : std::filesystem::recursive_directory_iterator(dir)) {
				std::error_code ec;
				if (entry.is_regular_file(ec)) {
					std::cout << " - " << entry.path().string() << std::endl;
				}
			}
		}
		catch (...) {
			std::cout << "(无法列出文件或目录不存在)" << std::endl;
		}
	}
};

// 生成自定义字典文件（示例）
void generateDictionaryFile(const std::string& filename) {
	std::ofstream file(filename);
	if (!file.is_open()) {
		std::cerr << "❌ 无法创建字典文件: " << filename << std::endl;
		return;
	}
	for (int i = 0; i < 10000; ++i) file << i << std::endl;
	for (char c1 = 'a'; c1 <= 'z'; ++c1) {
		file << c1 << std::endl;
		for (char c2 = 'a'; c2 <= 'z'; ++c2) {
			file << std::string(1, c1) + c2 << std::endl;
			for (char c3 = 'a'; c3 <= 'z'; ++c3) {
				file << std::string(1, c1) + c2 + c3 << std::endl;
			}
		}
	}
	file.close();
	std::cout << "✅ 已生成字典文件: " << filename << std::endl;
}

int main() {
	std::cout << "🔓 7z压缩包密码破解工具 (修正版)" << std::endl;
	std::cout << "======================================" << std::endl;

	if (!SevenZipCracker::check7zAvailable()) {
		std::cerr << "❌ 未找到7z程序，请安装7-Zip 并确保 7z 在 PATH 中。" << std::endl;
		std::cout << "下载: https://www.7-zip.org/" << std::endl;
		return 1;
	}
	std::cout << "✅ 7z 程序可用" << std::endl;

	std::string zipFile;
	std::cout << "请输入7z压缩包文件路径: ";
	std::getline(std::cin, zipFile);

	if (!std::filesystem::exists(zipFile)) {
		std::cerr << "❌ 文件不存在: " << zipFile << std::endl;
		return 1;
	}
	std::cout << "✅ 找到压缩包文件: " << zipFile << std::endl;

	SevenZipCracker cracker(zipFile);
	bool success = false;

	while (!success) {
		std::cout << "\n" << std::string(50, '=') << std::endl;
		std::cout << "请选择破解模式:" << std::endl;
		std::cout << "1. 常用密码攻击 (推荐首选)" << std::endl;
		std::cout << "2. 字典攻击" << std::endl;
		std::cout << "3. 数字暴力破解 (1-6位)" << std::endl;
		std::cout << "4. 小写字母暴力破解 (1-4位)" << std::endl;
		std::cout << "5. 混合字符暴力破解 (1-4位)" << std::endl;
		std::cout << "6. 生成字典文件" << std::endl;
		std::cout << "0. 退出程序" << std::endl;
		std::cout << "请选择 (0-6): ";

		int choice = -1;
		if (!(std::cin >> choice)) {
			// 清理错误并跳过
			std::cin.clear();
			std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
			std::cerr << "❌ 无效输入，请输入数字 0-6" << std::endl;
			continue;
		}
		// 清除剩余行
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

		if (choice == 0) {
			std::cout << "👋 感谢使用，再见！" << std::endl;
			cracker.showStats();
			return 0;
		}

		switch (choice) {
		case 1:
			std::cout << "\n🎯 开始常用密码攻击..." << std::endl;
			success = cracker.commonPasswordAttack();
			break;
		case 2: {
			std::string dictFile;
			std::cout << "请输入字典文件路径: ";
			std::getline(std::cin, dictFile);
			std::cout << "\n🎯 开始字典攻击..." << std::endl;
			success = cracker.dictionaryAttack(dictFile);
			break;
		}
		case 3:
			std::cout << "\n🎯 开始数字暴力破解..." << std::endl;
			success = cracker.bruteForceNumeric(6);
			break;
		case 4:
			std::cout << "\n🎯 开始小写字母暴力破解..." << std::endl;
			success = cracker.bruteForceLowercase(4);
			break;
		case 5:
			std::cout << "\n🎯 开始混合字符暴力破解..." << std::endl;
			success = cracker.bruteForceMixed(4);
			break;
		case 6:
			generateDictionaryFile("password_dict.txt");
			std::cout << "✅ 字典文件已生成，请使用选项2进行字典攻击" << std::endl;
			continue;
		default:
			std::cerr << "❌ 无效选择，请重新选择" << std::endl;
			continue;
		}

		cracker.showStats();

		if (!success) {
			std::cout << "\n❌ 当前方法未找到密码" << std::endl;
			char cont;
			std::cout << "是否继续尝试其他方法？(y/n): ";
			std::cin >> cont;
			std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
			if (cont != 'y' && cont != 'Y') {
				std::cout << "👋 感谢使用，再见！" << std::endl;
				break;
			}
		}
	}

	if (success) {
		std::cout << "\n🎉 恭喜！密码破解成功！" << std::endl;
		std::cout << "📁 若需要保留解压文件，请复制或移动临时目录下的文件：" << std::endl;
		std::cout << "   （临时目录名已打印或为 temp_extract_xxx）" << std::endl;
	}
	else {
		std::cout << "\n😞 未能破解密码，请尝试其他方法或回忆更多密码线索" << std::endl;
	}

	std::cout << "\n按回车键退出..." << std::endl;
	std::cin.get();
	return success ? 0 : 1;
}
